package gcr

import (
        "context"
        "errors"
        "fmt"
        "os"
        "strings"
    
        "cloud.google.com/go/storage"
        "github.com/keel-hq/keel/extension/credentialshelper"
        "github.com/keel-hq/keel/types"
        "golang.org/x/oauth2/google"
)

func init() {
        credentialshelper.RegisterCredentialsHelper("gcr", New())
}

type CredentialsHelper struct {
        enabled bool
}

func New() *CredentialsHelper {
        return &CredentialsHelper{
            enabled: true,
        }
}

func (h *CredentialsHelper) IsEnabled() bool {
        return h.enabled
}

func (h *CredentialsHelper) GetCredentials(image *types.TrackedImage) (*types.Credentials, error) {
        if !h.enabled {
            return nil, errors.New("not initialised")
        }
    
        if !strings.HasPrefix(image.Image.Registry(), "gcr.io") && !strings.Contains(image.Image.Registry(), "pkg.dev") {
            return nil, credentialshelper.ErrUnsupportedRegistry
        }
    
        if credentials, err := readCredentialsFromFile(); err == nil {
            return credentials, nil
        }
    
        return getWorkloadIdentityTokenCredentials()
}

func readCredentialsFromFile() (*types.Credentials, error) {
        credentialsFile, ok := os.LookupEnv("GOOGLE_APPLICATION_CREDENTIALS")
        if !ok {
            return nil, errors.New("GOOGLE_APPLICATION_CREDENTIALS environment variable not set")
        }
    
        credentials, err := os.ReadFile(credentialsFile)
        if err != nil {
            return nil, fmt.Errorf("failed to read credentials file: %w", err)
        }
    
        return &types.Credentials{
            Username: "_json_key",
            Password: string(credentials),
        }, nil
}

func getWorkloadIdentityTokenCredentials() (*types.Credentials, error) {
        ctx := context.Background()
        tokenSource, err := google.DefaultTokenSource(ctx, storage.ScopeReadOnly)
        if err != nil {
            return nil, fmt.Errorf("failed to get default token source: %w", err)
        }
        token, err := tokenSource.Token()
        if err != nil {
            return nil, fmt.Errorf("failed to get token: %w", err)
        }
    
        return &types.Credentials{
            Username: "_token",
            Password: token.AccessToken,
        }, nil
}
